package com.jamy.song.demo.config;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.URL;

@Configuration
public class EsConfig implements InitializingBean {

    @Value("${es.config.cluster-name}")
    private String esClusterName;
    @Value("${es.config.cluster-nodes}")
    private String esClusterNodes;
    @Value("${es.config.username}")
    private String esUserName;
    @Value("${es.config.password}")
    private String esPassword;
    @Value("${es.config.index}")
    private String index;
    @Value("${es.config.connection-request-timeout}")
    private int esConnectionRequestTimeout;
    @Value("${es.config.connect-timeout}")
    private int esConnectTimeout;
    @Value("${es.config.socket-timeout}")
    private int esSocketTimeout;


    @Value("${es.pool.max-total}")
    private int maxTotal;
    @Value("${es.pool.max-idle}")
    private int maxIdle;
    @Value("${es.pool.min-idle}")
    private int minIdle ;

    public static String ES_CLUSTER_NAME = "";
    public static String ES_CLUSTER_NODES = "";
    public static String ES_USERNAME = "";
    public static String ES_PASSWORD = "";
    public static String ES_INDEX = "";
    public static int ES_CONNECTION_REQUEST_TIMEOUT = -1;
    public static int ES_CONNECT_TIMEOUT = -1;
    public static int ES_SOCKET_TIMEOUT = -1;


    public static int MAX_TOTAL = 8;
    public static int MAX_IDLE = 8;
    public static int MIN_IDLE = 1;


    @Override
    public void afterPropertiesSet() {
        ES_CLUSTER_NAME = esClusterName;
        ES_CLUSTER_NODES = esClusterNodes;
        ES_USERNAME = esUserName;
        ES_PASSWORD = esPassword;
        ES_INDEX = index;
        ES_CONNECTION_REQUEST_TIMEOUT = esConnectionRequestTimeout;
        ES_CONNECT_TIMEOUT = esConnectTimeout;
        ES_SOCKET_TIMEOUT = esSocketTimeout;

        MAX_TOTAL = maxTotal;
        MAX_IDLE = maxIdle;
        MIN_IDLE = minIdle;
    }

    @Bean
    public GenericObjectPoolConfig config() {
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMinIdle(EsConfig.MIN_IDLE);
        poolConfig.setMaxTotal(EsConfig.MAX_TOTAL);
        poolConfig.setMaxIdle(EsConfig.MAX_IDLE);
        poolConfig.setJmxEnabled(false);
        return poolConfig;
    }

    @Bean
    public GenericObjectPool<RestHighLevelClient> pool(
            PooledObjectFactory<RestHighLevelClient> factory,
            GenericObjectPoolConfig config) {
        return new GenericObjectPool<>(factory, config);
    }

    @Bean
    public PooledObjectFactory<RestHighLevelClient> factory() {
        return new BasePooledObjectFactory<RestHighLevelClient>() {

            @Override
            public void destroyObject(PooledObject<RestHighLevelClient> pooledObject) throws Exception {
                RestHighLevelClient highLevelClient = pooledObject.getObject();
                highLevelClient.close();
            }

            @Override
            public RestHighLevelClient create() throws Exception {

                String[] urlList = EsConfig.ES_CLUSTER_NODES.split(",");
                HttpHost[] nodes = new HttpHost[urlList.length];
                for (int i = 0; i < urlList.length; i++) {
                    URL url = new URL(urlList[i]);
                    HttpHost node = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
                    nodes[i] = node;
                }

                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(EsConfig.ES_USERNAME, EsConfig.ES_PASSWORD));

                return new RestHighLevelClient(RestClient.builder(nodes)
                        .setRequestConfigCallback(
                                requestConfigBuilder -> {
                                    requestConfigBuilder.setConnectTimeout(EsConfig.ES_CONNECT_TIMEOUT);
                                    requestConfigBuilder.setSocketTimeout(EsConfig.ES_SOCKET_TIMEOUT);
                                    requestConfigBuilder.setConnectionRequestTimeout(EsConfig.ES_CONNECTION_REQUEST_TIMEOUT);
                                    return requestConfigBuilder;
                                }
                        ).setHttpClientConfigCallback(
                                httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                        )
                );
            }

            @Override
            public PooledObject<RestHighLevelClient> wrap(RestHighLevelClient restHighLevelClient) {
                return new DefaultPooledObject<>(restHighLevelClient);
            }
        };
    }

}

